//   Copyright 2012,2013 Vaughn Vernon
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package com.saasovation.collaboration.domain.model;

import com.saasovation.collaboration.CollaborationAppTest;
import com.saasovation.collaboration.application.ApplicationTestBase;
import com.saasovation.collaboration.port.adapter.persistence.StorageCleaner;
import com.saasovation.collaboration.port.adapter.spring.RabbitEventTrackingConfiguration;
import com.saasovation.common.TestBase;
import com.saasovation.common.annotation.TestContainers;
import com.saasovation.common.domain.model.DomainEvent;
import com.saasovation.common.domain.model.DomainEventPublisher;
import com.saasovation.common.domain.model.DomainEventSubscriber;
import com.saasovation.common.domain.model.EventTracking;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

import java.util.ArrayList;
import java.util.HashMap;

import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

@SpringBootTest(classes = CollaborationAppTest.class, webEnvironment = RANDOM_PORT)
@TestContainers(use = true)
@ActiveProfiles("test")
@Import(RabbitEventTrackingConfiguration.class)
public abstract class DomainTestBase extends TestBase {

    @Autowired
    protected StorageCleaner storageCleaner;

    @Autowired
    protected EventTracking eventTracking;

    protected DomainTestBase() {
        super();
    }

    @DynamicPropertySource
    public static void dataSourceProperties(DynamicPropertyRegistry registry) {
        if (!useTestContainers(ApplicationTestBase.class)) {
            return;
        }
        initMySqlContainer(registry);
        initRabbitMqContainer(registry);
    }

    @BeforeEach
    protected void setUp() throws Exception {
        DomainEventPublisher.instance().reset();
        DomainEventPublisher.instance().subscribe(new DomainEventSubscriber<>() {
            @Override
            public void handleEvent(DomainEvent aDomainEvent) {
                eventTracking.handledEvents().add(aDomainEvent.getClass());
            }

            @Override
            public Class<DomainEvent> subscribedToEventType() {
                return DomainEvent.class;
            }
        });
        // At beginning of the test, give MQExchangeListeners time to receive
        // messages from queues which were published by previous tests.
        // Since RabbitMQ Java Client does not allow queue listing or cleaning
        // all queues at once, we can just consume all messages and do
        // nothing with them as a work-around.
        Thread.sleep(200L);
        this.eventTracking.setHandledEvents(new ArrayList<>());
        this.eventTracking.setHandledNotifications(new HashMap<>());
    }

    @AfterEach
    protected void tearDown() {
        storageCleaner.clean();
    }
}
